////////////////////////////////////////////////////////////////////////
//MCMC_EdgeOp.h
//
// edge operator: Log
//				  Canny
//
// Author: Zhuowen Tu
////////////////////////////////////////////////////////////////////////

#ifndef _MC_EDGEOP_H
#define _MC_EDGEOP_H

#define TUs_CANNY 1

#include "mcRasterColor.h"

////////////////////////////////////////////////////////////////////////
class MCMC_Pos
{
public:
	MCMC_Pos(){i=0; j=0;};
	MCMC_Pos(const int ii, const int jj){i=ii; j=jj;};

	MCMC_Pos & operator=(const MCMC_Pos &a);

public:
	int i;	// column
	int	j;	// row
};

////////////////////////////////////////////////////////////////////////
class MCMC_Edge: public LinkList<MCMC_Pos>
{
public:
	MCMC_Edge& operator=(const MCMC_Edge &a);

	void	AddAnEdgePoint(const int j, const int i);
};

////////////////////////////////////////////////////////////////////////
class MCMC_EdgeList
{
public:
	MCMC_EdgeList();
	~MCMC_EdgeList();
	
	int         GetEdgeNum() {return num_edge;}
	void		SetEdgeNum(const int num);
	MCMC_Edge*	GetFirst(void);
	MCMC_Edge*	GetNext(void);
	void		InsertEdgePoint(const int index, const int j, const int i);

protected:
	MCMC_Edge	*p_edge_list;
	int			num_edge;

private:
	int			move;
};


///////////////////////////////////////////////////////////////////////
class MCMC_Corner
{
public:
	MCMC_Corner();
	~MCMC_Corner();

	void			Create(const int num, const int n, const int m, mcmcVector<double> &vc_angle);
	inline int		NumBranches(void){return k;};
	inline double	GetBranch(const int i){if(i>=0 && i<k) return vc_angle(i); else return 0.0;};
	inline	int		J(void){return j;};
	inline int		I(void){return i;};

protected:
	int				j,i;
	int				k;		// number of branches
	mcmcVector<double>	vc_angle;
};

class MCMC_CornerList
{
public:
	MCMC_CornerList();
	~MCMC_CornerList();
	virtual	void	Free(void);

	void			Create(const int num);
	MCMC_Corner*	GetCorner(const int i);
	MCMC_Corner*	GetFirstCorner(void);
	MCMC_Corner*	GetNextCorner(void);
	void			GetnerateCornerMask(void);
	inline int		NumCorner(void){return num_corner;};

public:
	Raster<int>		ras_corner_mask;

protected:
	MCMC_Corner		*p_corners;
	int				num_corner;
	int				move;
};


class MCMC_OpAnEdge
{
public:
	MCMC_OpAnEdge(){;};
	
	MCMC_OpAnEdge & operator=(MCMC_OpAnEdge &a);
	void		CopyFrom(MCMC_OpAnEdge &a, int num);

	void		Empty(void){vc_points.SetDimension(0,0); list_pixels.Empty();};
	void		CopyFromPixelList(void);
	void		CopyToPixelList(void);

	inline	int NumPoints(void){return vc_points.size();};

	inline  int& i(int k){return vc_points(k).i;};
	inline	int& j(int k){return vc_points(k).j;};
	inline  int& x(int k){return vc_points(k).i;};
	inline	int& y(int k){return vc_points(k).j;};
	inline  bool	GetFirst(int &j, int &i){return list_pixels.GetFirst(j, i);};
	inline  bool	GetLast(int &j, int &i){return list_pixels.GetLast(j, i);};

	inline	void InsertPoint(int j, int i){list_pixels.Insert(j, i);};
	inline	void AddPoint(int j, int i){list_pixels.Insert(j, i); CopyFromPixelList();};
	void	ExpendTo(const int num_new_points);
	void	DeleteTheFirstPixel(void){list_pixels.DeleteTheFirstPixel(); CopyFromPixelList();};

public:
	SimpleMatrix<MCMC_Pos>	vc_points;
	MCMC_PixelSet			list_pixels;
};

class MCMC_OpEdges
{
public:

	MCMC_OpEdges & operator=(const MCMC_OpEdges &a)
	{
		if (this != &a)
			vc_edges = a.vc_edges;

		return *this;
	}

	void	SetNumEdges(int num){vc_edges.SetDimension(1, num);};
	inline  int	NumEdges(void){return vc_edges.size();};
	
	inline	MCMC_OpAnEdge&	Edge(int i){return vc_edges(i);};
	void	CopyFromPixelList(void)
	{
		for (int i=0; i<vc_edges.size(); i++)
			vc_edges(i).CopyFromPixelList();
	}
	void	CopyToPixelList(void)
	{
		for (int i=0; i<vc_edges.size(); i++)
			vc_edges(i).CopyToPixelList();
	}
	
	void	ToImage(Raster<int> &ras_edges, bool bone=false);


	SimpleMatrix<MCMC_OpAnEdge>		vc_edges;
};

//////////////////////////////////////////////////////////////////////
class MCMC_EdgeLinking
{
public:
	MCMC_EdgeLinking();
	~MCMC_EdgeLinking();
	
	void	ObtainAtomicRegions(Raster<double> &ras_canny, Raster<double> &Ix, Raster<double> &Iy, double scale);

	void	LinkEdges(const double th_low, const double th_high, const double min_len1);
	bool	NextPoint(int *rp, int *cp);
	void	ThinEdges(void);
	void	LabelJunctions(void);
	void	DetectedEdgesToImage(void);
	void	ConnectEdges(void);
	void	ExtendParallelEdges(MCMC_OpEdges &local_edges, int smooth, int max_ext);

	inline	int rows(void){return ras_gradient.rows();};
	inline  int	cols(void){return ras_gradient.cols();};
	inline	int	NumEdges(void){return detected_edges.NumEdges();};

protected:
	void	IlePropagate(Raster<int> &ras_edgemap, int x, int y, int d);
	int		NumNeighbors(Raster<int> &ras_image, int x, int y, int neighbourhood);
	void	ExtendEdgeNew(MCMC_OpAnEdge &edge_new, MCMC_OpAnEdge &edge_old, int end, int smooth, int ext);
	void	BrenDda(MCMC_OpAnEdge& edge_seg, int x1, int y1, int x2, int y2);
	void	handle_runedge(int run_edge_no, int cx, int cy, MCMC_OpEdges *start_extend,	MCMC_OpEdges *end_extend,
						   MCMC_OpEdges *start_use,	MCMC_OpEdges *end_use);
	void	LabelNumberOnEdgePixels(Raster<int> &ras_edgemap);


public:
	Raster<int>		ras_edges;
	Raster<double>	ras_gradient;

protected:
	double			threshold_low_linking;
	double			threshold_high_linking;
	double			min_len;

	Raster<double>	ras_angle;
	Raster<int>		ras_junctions;

	MCMC_OpEdges	detected_edges;

	int		dx[8],dy[8];
};

///////////////////////////////////////////////////////////////////////
// color image edge operators
class MCMC_EdgeOp: public Raster<double>
{
public:
	MCMC_EdgeOp();

	// operator
	MCMC_EdgeOp & operator=(const Raster<uchar> &I);
	MCMC_EdgeOp & operator=(const Raster<double> &I);

	// operations
	Raster<double> Canny(double sigma, double alfa=0.05, Raster<double> *pIx=NULL,Raster<double> *pIy=NULL, bool bSpecial=false);

private:
	int	dx[8],dy[8];
};



///////////////////////////////////////////////////////////////////////
// color image edge operators
class MCMC_EdgeOp_Color: public Raster_Color<double>
{
public:
	// construction & destruction
	MCMC_EdgeOp_Color();

	// operators
	MCMC_EdgeOp_Color & operator=(const MCMC_EdgeOp_Color &I);
	MCMC_EdgeOp_Color& operator=(const Raster_Color<uchar> &I);
	MCMC_EdgeOp_Color& operator=(const Raster_Color<double> &I);

	// operations
	Raster<double>	Canny(double sigma,double alfa,
						  Raster<double> *pIx=NULL,Raster<double> *pIy=NULL,
						  const bool	bSpecial=false);		// Canny operator
	void	ExtractEdges(MCMC_EdgeList &edge_list, double sigma, Raster<int> *pras_result=NULL);
	void	CornerDetection(double sigma,Raster<uchar> &ras_corner, Raster<uchar> &ras_edgemap,MCMC_CornerList &corner_list);
	void	RidgeEdgeSeeds(const double sigma, mcmcMatrix<uchar> &mx_ridge, mcmcMatrix<uchar> *pmx_edges=NULL);
	
public:

	void	LabelJunctions(Raster<int> &ras_edgemap);
	void	ile_propagate(Raster<int> &ras_edgemap, const int x, const int y, const int d);
	void	LabelNumberOnEdgePixels(Raster<int> &ras_edgemap);
	void	FormEdgeList(MCMC_EdgeList &edge_list, Raster<int> &ras_numbered_edgemap);

	// UNIVAR Detector and OMNIVAR Detector
	void	CornerClassification(Raster<double> &ras_Ix, Raster<double> &ras_Iy,
								 Raster<uchar> &ras_corner, Raster<uchar> &ras_edgemap,
								 MCMC_CornerList &corner_list);
private:
	int		DiscoverDirections(mcmcVector<double> &vc_vote, mcmcVector<int> &vc_index);
	double	calcPercentThreshold(cv::Mat mImage, float dPercent, int nBins);

private:
	int	dx[8],dy[8];
};



#endif
